/**
 * Author: YuBing 羽冰
 *  time : 2021/5/24
 * description: 建立websocket服务端
 * dependency module: ws
 *  note : 尚未完成
 */

// webSoket没写完, 掉线重连和消息补发也还没做
var _WebSocket = require("ws");

var webSocket, Sockets = {};
// webSocket服务端操作
// 建立单个webSocket通信
/* 还要再添加,使用noServer状态的单连接 */
function singleSocket(socketHandler, _server) {
  // 根据不同的类型设置不同的webSocket配置项
  var setting = "server";
  if (_server) {
    // 分3种情况,1是主机名(地址),2是服务器端口,3是外来服务器
    // 如果这两种情况都不匹配,那说明是外来服务器设置,那setting就没必要改变
    // 如果是域名,就不是http/https开头,而是ws开头
    if (typeof _server === "string") setting = "host";
    if (typeof _server === "number") setting = "port";
  }
  // ```````````````````````这里修改
  else _server = server;
  // ```````````````````````

  // 建立服务端webSocket
  webSocket = new _WebSocket.Server({
    [setting]: _server
  });

  // 当有浏览器连接上服务器时
  webSocket.on("connection", function (_ws, req) {
    console.log("webSocket连接成功");

    // 可以在这里,客户端连接成功的时候,用数组或对象区别记录存储下每一个接入的客户端
    // webSocket.clients就是这么来的

    // 标识存储每个ip
    var ip = req.socket.remoteAddress.split(":")[3]
    _ws.ip = ip;

    // 为每一个接入webSocket的客户端都添加信息事件
    // 客户端往服务端发送消息时,服务端被动式响应
    _ws.on("message", function (data) {
      // 如果客户端还是连接状态,使用client.send([sendSomething])发送消息
      socketHandler(_ws, data);
    })
  })

  // 服务器webSocket关闭时
  webSocket.on("close", function () {
    console.log("webSocket断开连接");
  });

  // webSocket出错时
  webSocket.on("error", function (err) {
    console.log("WebSocket Err!!!");
    console.log(err);
  })
}

// 建立多个webSocket
function manySockets(SocketSetting, _server) {
  // ``````````````````````这里修改
  try {
    var _WebSocket = require("ws");
    var url = require("url");
  } catch (err) {
    console.log(err);
    return;
  }
  //``````````````````````````````

  // 设置多个webSocket必须要先建立服务器
  // ```````````````````````````这里修改
  _server = _server || server;
  //`````````````````````````````

  for (var props in SocketSetting) {
    var Handler = SocketSetting[props].Handler;
    var urlLink = SocketSetting[props].url;
    var name = props;

    // 每个webSocket都是无服务器状态
    var _socket = new _WebSocket.Server({ noServer: true });

    // 服务器webSocket连接上时
    _socket.on("connection", function (_ws) {
      console.log("webSocket:" + props + " 连接成功");

      // 客户端往服务端发送消息时,服务端被动式响应
      _ws.on("message", function (data) {
        // 向每一个接入webSocket的客户端发送广播
        webSocket.clients.forEach(function (client) {
          if (client.readyState === _WebSocket.OPEN) {
            // 如果客户端还是连接状态
            // 使用client.send([sendSomething])发送消息
            Handler(client, data);
          }
        })
      })
    });

    // 服务器webSocket关闭时
    _socket.on("close", function () {
      console.log("webSocket:" + props + " 断开连接");
    });

    // webSocket出错时
    _socket.on("error", function (err) {
      console.log("webSocket:" + props + " Err!!!");
      console.log(err);
    });

    // 设置好了之后进行存储
    Sockets[name].socket = _socket;
    Sockets[name].url = urlLink;
  }

  /** 
   *  write down at 2020/12/8  21:50
   *  
   *  diy your own event by using module "events" in nodeJs:
   * 
   *  var EventEmitter = require('events').EventEmitter
      var emitter = new EventEmitter();
      emitter.on([eventType],[eventHandler]);
      emitter.emit([eventType],[argumentsOfEventHandler]);

      you can also use "extends" in ES6:

      const eventEmitter=require('events');
      class emitter extends eventEmitter{}
      const emitter=new MyEmitter();

      note1: an eventType can only add up to 10 listeners
          you can also change the maxLimit, but i don't recommend to do that

      note2: every eventHandler should have a name, so that you can remove it
              by using its name
          
      so by doing that, you can now replace the "upgrade" event to your own event, then emit it in your http nodeServer at a suitable time

      when you want to remove an event, you can do these:
      remove a handler on an event: 
          emitter.removeListener([eventType],[Handler])

      remove all handler on an event:
          emitter.removeListener([eventType])

      remove all event that has been listened :
          emitter.removeListener()
      
      when you want to know how many listeners have been added on an event:
      you can use
          emitter.listeners([eventType]).length
      or
          EventEmitter.listenerCount(emitter,[eventType])

      when you want to know if an event has been listened:
      you can know it by calling emitter.emit([eventType])
      it will return a boolean value "true" when an event has been listened
   */
  // 服务器的upgrade事件进行主动触发
  _server.on("upgrade", function (request, socket, head) {
    // 路径
    var pathname = url.parse(request.url).pathname;
    // upgrade事件是否有对应的webSocket回应
    var IS_LINK_WRONG = true;

    // 根据路径主动触发不同webSocket
    for (var key in Sockets) {
      // 如果连接匹配上了,就触发该webSocket的连接事件
      if (pathname === Sockets[key].url) {
        Sockets[key].socket.handleUpgrade(request, socket, head, function done(ws) {
          Sockets[key].socket.emit('connection', ws, request);
        });

        IS_LINK_WRONG = false;
        break;
      }
    }

    // 如果该次事件没有设置对应的webSocket回应就销毁流并关闭连接
    if (IS_LINK_WRONG) socket.destroy();
  });
}

// 服务端向客户端主动发送广播
function SocketSend(msg, list, socketName) {
  var _socket;
  if (socketName && socketName.constructor === String) {
    _socket = Sockets[name].socket;
  }
  else _socket = webSocket;

  _socket.clients.forEach(function (client) {
    // 传入清单就对清单的ip进行屏蔽不广播
    if (list && list.constructor === Array && list.some(item => item == client.ip)) return;
    else if (list && list.constructor === String && list == client.ip) return;

    if (client.readyState === 1) client.send(msg);
  });
}


module.exports = {
  singleWebSocket: function (socketHandler, _server) {
    singleSocket(socketHandler, _server);
  },
  webSockets: function (SocketSetting, _server) {
    manySockets(SocketSetting, _server);
  },
  webSocketSend: function (msg, list, socketName) {
    SocketSend(msg, list, socketName);
  }
}